package top.metaspace.concurrent.threadpool;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author panjun
 * @date 2018/6/22.
 * 简单实现的线程池，不保证线程安全，支持超时机制，有简单的拒绝策略
 */
public class MyThreadPool {

	private static ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(10);

	private final Set<Worker> workerSet = new HashSet<>();

	private boolean allowCoreThreadTimeOut = false;

	private long keepAlive;

	private int corePoolSize;

	public MyThreadPool(int corePoolSize,int maxPoolSize, long keepAlive, TimeUnit unit) {
		this.corePoolSize = corePoolSize;
		this.maxPoolSize = maxPoolSize;
		keepAlive = unit.toNanos(keepAlive);
	}

	public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
		this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
	}

	private int poolSize;
	private int maxPoolSize;

	public static void main(String[] args) {

		MyThreadPool threadPool = new MyThreadPool(3, 100,0L, TimeUnit.SECONDS);

		for (int i = 0; i < 100; i++) {
			final int a = i;
			threadPool.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(1000);
						System.out.println("执行新任务 i:" + a + "   线程id:" + Thread.currentThread().getId());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}


	}

	public void execute(Runnable runnable) {
		if (poolSize < corePoolSize) {
			addThread(runnable);
		} else if(poolSize>=corePoolSize&&poolSize<maxPoolSize){

			if (!blockingQueue.offer(runnable)) {
				//队列加入失败
				addThread(runnable);
			}
		}else {
			//拒绝
			throw new RuntimeException("任务被拒绝");
		}

	}

	private class Worker implements Runnable {

		private Runnable firstTask;
		private Thread thread;

		public Worker(Runnable firstTask) {
			this.firstTask = firstTask;
		}

		@Override
		public void run() {
			Runnable task = firstTask;
			firstTask = null;
			while (task != null || (task = getTask()) != null) {
				task.run();
				task = null;
			}
			System.out.println("线程"+Thread.currentThread().getName()+"结束");
			poolSize--;

		}

		private Runnable getTask() {

			try {
				while (true) {
					Runnable r;
					if (poolSize > corePoolSize || allowCoreThreadTimeOut) {
						r = blockingQueue.poll(keepAlive, TimeUnit.NANOSECONDS);
						return r;
					} else {
						r = blockingQueue.take();
						return r;
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return null;

		}
	}

	public void addThread(Runnable runnable) {
		Worker worker = new Worker(runnable);
		workerSet.add(worker);
		Thread t = new Thread(worker);
		worker.thread = t;
		t.start();
		poolSize++;
	}


}

